package xcu.lxj.nettychat.chat.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.CollectionUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.stereotype.Service;
import xcu.lxj.nettychat.chat.dao.ContactDao;
import xcu.lxj.nettychat.chat.dao.MessageDao;
import xcu.lxj.nettychat.chat.dao.RoomDao;
import xcu.lxj.nettychat.chat.domain.dto.MsgReadInfoDTO;
import xcu.lxj.nettychat.chat.domain.entity.Contact;
import xcu.lxj.nettychat.chat.domain.entity.Message;
import xcu.lxj.nettychat.chat.domain.vo.request.*;
import xcu.lxj.nettychat.chat.domain.vo.request.member.MemberReq;
import xcu.lxj.nettychat.chat.domain.vo.response.ChatMemberResp;
import xcu.lxj.nettychat.chat.domain.vo.response.ChatMessageReadResp;
import xcu.lxj.nettychat.chat.domain.vo.response.ChatMsgResp;
import xcu.lxj.nettychat.chat.service.adapter.MessageAdapter;
import xcu.lxj.nettychat.chat.service.adapter.RoomAdapter;
import xcu.lxj.nettychat.chat.service.inter.ChatService;
import xcu.lxj.nettychat.chat.service.inter.ContactService;
import xcu.lxj.nettychat.chat.service.strategy.MsgHandlerFactory;
import xcu.lxj.nettychat.chat.service.strategy.msg.AbstractMsgHandler;
import xcu.lxj.nettychat.common.domain.vo.response.CursorPageBaseResp;
import xcu.lxj.nettychat.common.event.MessageSendEvent;

import javax.annotation.Nullable;
import java.util.*;

/**
 * @Author XinJian Lei
 * @Date 2024/9/28 17:25
 * @Version 1.0
 */
@Service
public class ChatServiceImpl implements ChatService {

    @Autowired
    private MessageDao messageDao;
    @Autowired
    private ApplicationEventPublisher applicationEventPublisher;
    @Autowired
    private ContactDao contactDao;
    @Autowired
    private RoomDao roomDao;
    @Autowired
    private ContactService contactService;



    @Override
    public Long sendMsg(ChatMsgReq request, Long uid) {
        // 1. 根据对应的类型找到对应的 策略去消费
        AbstractMsgHandler<?> msgHandler = MsgHandlerFactory.getStrategyNoNull(request.getMsgType());
        Long msgId = msgHandler.checkAndSaveMsg(request, uid);
        //2. 根据消息id 发送消息
        applicationEventPublisher.publishEvent(new MessageSendEvent(this,msgId));
        return msgId;
    }

    @Override
    public ChatMsgResp getMsgResp(Long msgId, Long receiveUid) {
        Message msg = messageDao.getById(msgId);
        return getMsgResp(msg, receiveUid);
    }

    @Override
    public ChatMsgResp getMsgResp(Message message, Long receiveUid) {
        return CollUtil.getFirst(getMsgRespBatch(Collections.singletonList(message), receiveUid));
    }

    /**
     * 适配器批量 构建ChatMsgResp
     * @param messages 消息列表
     * @param receiveUid 接收人id
     * @return List<ChatMsgResp>
     */
    public List<ChatMsgResp> getMsgRespBatch(List<Message> messages, Long receiveUid) {
        if (CollectionUtil.isEmpty(messages)) {
            return new ArrayList<>();
        }
        //查询消息标志
        return MessageAdapter.buildMsgResp(messages, receiveUid);
    }

    @Override
    public CursorPageBaseResp<ChatMsgResp> getMsgPage(ChatMessagePageReq request, @Nullable Long receiveUid) {
        //用最后一条消息id，来限制被踢出的人能看见的最大一条消息
        Long lastMsgId = getLastMsgId(request.getRoomId(), receiveUid);
        // 消息id 和 消息创建时间都能作为排序条件
        CursorPageBaseResp<Message> cursorPage = messageDao.getCursorPage(request.getRoomId(), request, lastMsgId);
        if (cursorPage.isEmpty()) {
            return CursorPageBaseResp.empty();
        }
        return CursorPageBaseResp.init(cursorPage, getMsgRespBatch(cursorPage.getList(), receiveUid));
    }

    /**
     * 获取最后的消息id
     * @param roomId 房间号
     * @param receiveUid 接收人id
     * @return
     */
    private Long getLastMsgId(Long roomId, Long receiveUid) {
        Contact contact = contactDao.get(receiveUid, roomId);
        return contact.getLastMsgId();
    }

    @Override
    public void recallMsg(Long uid, ChatMessageBaseReq request) {
//        Message message = messageDao.getById(request.getMsgId());
//        //校验能不能执行撤回
//        checkRecall(uid, message);
//        //执行消息撤回
//        recallMsgHandler.recall(uid, message);
    }



    @Override
    public Collection<MsgReadInfoDTO> getMsgReadInfo(Long uid, ChatMessageReadInfoReq request) {

        List<Message> messages = messageDao.listByIds(request.getMsgIds());
//        messages.forEach(message -> {
//            AssertUtil.equal(uid, message.getFromUid(), "只能查询自己发送的消息");
//        });
        return contactService.getMsgReadInfo(messages).values();
    }

    @Override
    public CursorPageBaseResp<ChatMessageReadResp> getReadPage(Long uid, ChatMessageReadReq request) {
        Message message = messageDao.getById(request.getMsgId());
//        AssertUtil.isNotEmpty(message, "消息id有误");
//        AssertUtil.equal(uid, message.getFromUid(), "只能查看自己的消息");
        CursorPageBaseResp<Contact> page;
        if (request.getSearchType() == 1) {//已读
            page = contactDao.getReadPage(message, request);
        } else {
            page = contactDao.getUnReadPage(message, request);
        }
        if (CollectionUtil.isEmpty(page.getList())) {
            return CursorPageBaseResp.empty();
        }
        return CursorPageBaseResp.init(page, RoomAdapter.buildReadResp(page.getList()));
    }

    @Override
    public void msgRead(Long uid, ChatMessageMemberReq request) {
        Contact contact = contactDao.get(uid, request.getRoomId());
        if (Objects.nonNull(contact)) {
            Contact update = new Contact();
            update.setId(contact.getId());
            update.setReadTime(new Date());
            contactDao.updateById(update);
        } else {
            Contact insert = new Contact();
            insert.setUid(uid);
            insert.setRoomId(request.getRoomId());
            insert.setReadTime(new Date());
            contactDao.save(insert);
        }
    }


    @Override
    public CursorPageBaseResp<ChatMemberResp> getMemberPage(List<Long> memberUidList, MemberReq request) {
        return null;
    }

}
